<?php
namespace app\extensions\lib\push;
use app\exception\ApiException;
use app\extensions\api\Oss;
use app\extensions\lib\Message;
use app\model\TokenInfo;
use app\queue\redis\shushu\RequestEvent;
use OSS\Core\OssException;
use support\Db;
use support\Log;
use Webman\RedisQueue\Redis;

class Push
{
    const TAPPLUS_ADMIN_CHANNEL = 'tapplus_admin';
    //支持记录推送的用户地址的渠道
    const PUSH_UDID_URL = [
        self::TAPPLUS_ADMIN_CHANNEL,
    ];

    //内部渠道
    const PUSH_INNER = [
        self::TAPPLUS_ADMIN_CHANNEL,
    ];

    public static function getBlackList($request_id){
        return $request_id.'__black_list';
    }

    public static function getRequestData($request_id){
        return $request_id.'__data_';
    }

    public static function getPayloadKey($request_id){
        return $request_id.'__payload_key';
    }

    public static function formatMessage($push_data_public,$push_payloads){

    }


    /**
     * @param $userList
     * @param $data
     * @param bool $is_async
     * @param string $request_id
     * @param array $messages sdk的消息体(已经baseFormat 处理好的
     * @param string $info 记录信息
     * @return array
     */
    public function push($userList,$data,$is_async=true,$request_id='',$messages=[],$info=''){
        //推送公共字段
        if(!$messages){
            $notificationColumns = ['notification','custom_data','version'];
            $notificationData = [];

            foreach ($notificationColumns as $column){
                $values = [];
                if(isset($data[$column])){
                    //json 转数组
                    $tmp = is_string($data[$column]) ? json_decode($data[$column],true): $data[$column];
                    if($tmp){
                        $notificationData[$column] = $tmp;
                        continue;
                    }
                }
                $notificationData[$column] = $values;
            }
            $notificationData['message_type'] = $data['message_type'] ?? 0;
            $messages = $this->baseFormat($notificationData);
        }
        if(env('APP_ENV')!='production'){
            dump($userList,$messages,$is_async);
        }
        !$request_id && $request_id = requestId();
        $iosReturn = $androidReturn = $huaweiReturn = [];
        $delay = 0;
        foreach ($userList as $os_id => $items){
            $message = $messages[$os_id];
            foreach ($items as $package_id => $item){
                $delay += 1;
                $tokens = $item['tokens'];//默认包对应的，token集
                $udids = $item['udids'] ?? '';//默认包对应的，uid集(不一定有)
                if(empty($tokens)) continue;
                $item['is_async'] = $is_async;
                if($os_id==1){
                    $message['message']['tokens'] = $tokens;//设备token 在数据里
                    $message['message']['udids'] = $udids;//设备 在数据里
                }
                if($is_async){
                    $tokensArr = explode(',',$tokens);
                    $udidsArr = explode(',',$udids);
                    $maxPackageSize = 100;//包长
                    $tokensList = array_chunk($tokensArr,$maxPackageSize);
                    $udidsList = array_chunk($udidsArr,$maxPackageSize);
                    $count = count($tokensList);
                    $sum = count($tokensArr);
                    foreach ($tokensList as $key =>$newTokens){
                        //重设新的token
                        $tokens = $item['tokens'] = implode(',',$newTokens);
                        $udids = $item['udids'] = implode(',',$udidsList[$key]);
                        if($os_id==1){
                            $message['message']['tokens'] = $tokens;//设备token 在数据里
                            $message['message']['udids'] = $udids;//设备id 在数据里
                        }
                        $chunkInfo = $info."chunk_page:-$sum:{$key}:$maxPackageSize:times:$count";
                        Redis::send(\app\queue\redis\push\Push::$update_redis_queue_key,array_merge([],
                            compact('os_id','item','message','request_id','chunkInfo')));

                    }


                }else{
                    try{
                        if($os_id==1) {
                            $androidReturn[$item['package_id']] = AndroidPush::push($item,$message,$request_id);
                        }elseif($os_id==2) {
                            $iosReturn[$item['package_id']] = IosPush::push($item,$message,$request_id);
                        }elseif($os_id==3) {
                            $huaweiReturn[$item['package_id']] = HmsPush::push($item,$message,$request_id);
                        }
                    }catch (ApiException $apiException){
                        Log::error('error::request_id:'.$request_id.':'.$apiException->getMessage());
                    }
                }


            }

        }
        return compact('iosReturn','androidReturn','huaweiReturn','request_id');
    }

    private static function baseFormat($notificationData)
    {
        //设置基本通知字段
        $notification = $notificationData['notification'] ?? [];
        $data = $notificationData['custom_data'] ?? [];
        $version = $notificationData['version'] ?? '';
        $message_type = $notificationData['message_type'] ?? 0;//默认有通知

        $old = Message::get();
        Message::setVersion($version);
        Message::setNotification($notification);
        //防止 设置sound，image，color 特换掉
        isset($data['android_option']) && Message::setAndroid($data['android_option']);//android 下的配置
        isset($data['android_notification']) && Message::setAndroidNotification($data['android_notification']);//android.notification 下的配置

        isset($data['sound']) && Message::setSound($data['sound']);
        isset($data['image']) && Message::setImage($data['image']);
        isset($data['color']) && $data['color'] && Message::setColor($data['color']);
        isset($data['badge']) && Message::setBadge($data['badge']);
        isset($data['setSubtitle']) && Message::setSubtitle($data['setSubtitle']);
        isset($data['ios_option']) && Message::setIos($data['ios_option']);//aps.alert 下的配置


        isset($data['ios_notification']) && Message::setIosNotification($data['ios_notification']);//aps 下的配置
        isset($data['data']) && Message::setData($data['data']);//安卓data,ios 最外参透传
        isset($data['fcm_option']) && Message::setFcmOption($data['fcm_option']);//安卓data,ios 最外参透传
        Message::setType($message_type);
        $result =  Message::get();
        Message::init($old);

        return $result;
    }

    public static function finishRequestPush($request_id,$cate_id,$channel=''){
        if(!in_array($channel,Push::PUSH_INNER)){
            self::deleteTmpData($request_id);
            return;
        }
        $RequestEvent = new RequestEvent();
        $properties = [
            'finish_time' => date('Y-m-d H:i:s'),
        ];
        if(!$cate_id){
            Log::channel('request')->warning('finishRequestPush::no cate_id--'.$request_id);
            return;
        }
        $is_add = false;
        \Webman\RedisQueue\Redis::send($RequestEvent->queue,array_merge([],
            compact('cate_id','request_id','properties','is_add')));


        //回调完成地址
        $callback_url = Redis::hGet(self::getRequestData($request_id),'callback_url');
        $udid_url = Oss::DOMAIN.'/'.self::pushUidUrl($request_id);
        $return = '';
        try{
            $callback_url && $return = curl($callback_url, ['request_id'=>$request_id,'cate_id'=>$cate_id,'udid_url'=>$udid_url], 1, [], [], [], false,5);
            //dump($return);
        }catch (\Throwable $exception){
            //dump($exception->getMessage());
            Log::channel('request')->error("callback_url::$request_id:$cate_id:$callback_url".json_encode($return));
        }
        self::deleteTmpData($request_id);
        Log::channel('request')->info("finishRequestPush::$request_id:$cate_id:$callback_url".json_encode($properties).':return:'.json_encode($return));
    }

    public static function deleteTmpData($request_id){
        \support\Redis::del(
            self::getBlackList($request_id),
            self::getRequestData($request_id),
            self::getPayloadKey($request_id)
        );
    }

    public static function pushUidUrl($request_id){
        return  'tapplus_push/push_udid/'.$request_id.'.csv';
    }

    public static function saveUidUrl($request_id,$udids){
        $datasKey = self::getRequestData($request_id);
        $postition = Redis::hGet($datasKey,'position') ?: 0;
        $callbackUrl = trim(env('APP_URL'),'/').'/oss/request_udid_oss_callback';
        $ossPath = self::pushUidUrl($request_id);
        $param = ['request_id'=>$request_id,'object'=>$ossPath];
        $Oss = new \app\extensions\api\Oss();
        //$Oss->deleteObject($ossPath);
        $contents = [
            is_array($udids) ? implode("\n",$udids) : $udids
        ];
        $url = $Oss::DOMAIN.'/'.$ossPath;
        try{
            $postition = $Oss->uploadContentsCallback($contents,$ossPath,$param,$callbackUrl,$postition);
        } catch (OssException $e) {
            // 捕获异常主体
            Log::channel('request')->warning($request_id.':saveUidUrl'.$e->getMessage());
        } catch (\Throwable $e) {
            // 捕获异常主体
            Log::channel('request')->error($request_id.':saveUidUrl'.$e->getMessage());
        }
        Redis::hSet($datasKey,'position',$postition);
    }

}